package com.lh.common.utils;

import io.netty.channel.ConnectTimeoutException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;

import javax.activation.MimetypesFileTypeMap;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

/**
 * @Description: Http请求的工具类
 * @author TangCai
 * @date 2016年11月3日 上午11:00:27
 * @version V1.0
 */
public final class HttpUtil {
	protected static Logger logger = LoggerFactory.getLogger(HttpUtil.class);

    /**
     * Http Get请求
     *
     * @param url         请求地址
     * @param charset     返回数据编码
     * @param connTimeout 连接超时时间
     * @param soTimeout   读取数据超时时间
     * @return
     */
    public static String httpGet(String url, String charset, int connTimeout, int soTimeout) {
        String result = null;
        GetMethod getMethod = null;
        try {

            HttpClient httpClient = new HttpClient();
            getMethod = new GetMethod(url);
            HttpMethodParams methodParams = getMethod.getParams();
            // 使用系统提供的默认的恢复策略
            methodParams.setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
            // 设置返回内容编码
            methodParams.setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, charset);
            // 设置参数
            HttpConnectionManagerParams managerParams = httpClient.getHttpConnectionManager().getParams();
            // 设置连接超时时间(单位毫秒)
            managerParams.setConnectionTimeout(connTimeout);
            // 设置读数据超时时间(单位毫秒)
            managerParams.setSoTimeout(soTimeout);
            httpClient.executeMethod(getMethod);
            if (getMethod.getStatusCode() == HttpStatus.SC_OK) {
                result = castString(getMethod.getResponseBodyAsStream(), charset);
            }
        } catch (ConnectTimeoutException e) {
        	result = null;
            logger.error(url + ", 连接超时");
        } catch (SocketTimeoutException e) {
        	result = null;
            logger.error(url + ", 响应超时");
        } catch (Exception e) {
        	result = null;
        	e.printStackTrace();
            logger.error(url + ", Http Get请求异常！", e);
        } finally {
            if (getMethod != null) {
                getMethod.releaseConnection();
            }
        }
        return result;
    }

    /**
     * Http Post请求
     *
     * @param url         请求地址
     * @param params      请求参数
     * @param connTimeout 连接超时时间
     * @param soTimeout   读取数据超时时间
     * @return
     */
    public static String httpPost(String url, Map<String, String> params, int connTimeout, int soTimeout) {
        String result = null;
        PostMethod postMethod = null;
        try {
            HttpClient httpClient = new HttpClient();
            postMethod = new PostMethod(url);
            HttpMethodParams methodParams = postMethod.getParams();
            // 使用系统提供的默认的恢复策略
            methodParams.setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
            // 设置返回内容编码
            methodParams.setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
            // 设置参数
            HttpConnectionManagerParams managerParams = httpClient.getHttpConnectionManager().getParams();
            // 设置连接超时时间(单位毫秒)
            managerParams.setConnectionTimeout(connTimeout);
            // 设置读数据超时时间(单位毫秒)
            managerParams.setSoTimeout(soTimeout);
            if (params != null) {
                for (Entry<String, String> param : params.entrySet()) {
                    postMethod.addParameter(new NameValuePair(param.getKey(), param.getValue()));
                }
            }
            httpClient.executeMethod(postMethod);
            if (postMethod.getStatusCode() == HttpStatus.SC_OK) {
                result = castString(postMethod.getResponseBodyAsStream());
            }
        } catch (ConnectTimeoutException e) {
            logger.error(url + ", 连接超时");
        } catch (SocketTimeoutException e) {
            logger.error(url + ", 响应超时");
        } catch (Exception e) {
            logger.error(url + ", Http Post请求异常！", e);
        } finally {
            if (postMethod != null) {
                postMethod.releaseConnection();
            }
        }
        return result;
    }

    /**
     * Http Post请求
     *
     * @param url         请求地址
     * @param entity      请求参数
     * @param connTimeout 连接超时时间
     * @param soTimeout   读取数据超时时间
     * @return
     */
    public static String httpPost(String url, RequestEntity entity, int connTimeout, int soTimeout) {
        String result = null;
        PostMethod postMethod = null;
        try {
            HttpClient httpClient = new HttpClient();
            postMethod = new PostMethod(url);
            HttpMethodParams methodParams = postMethod.getParams();
            // 使用系统提供的默认的恢复策略
            methodParams.setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
            // 设置返回内容编码
            methodParams.setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
            // 设置参数
            HttpConnectionManagerParams managerParams = httpClient.getHttpConnectionManager().getParams();
            // 设置连接超时时间(单位毫秒)
            managerParams.setConnectionTimeout(connTimeout);
            // 设置读数据超时时间(单位毫秒)
            managerParams.setSoTimeout(soTimeout);
            if (entity != null) {
                postMethod.setRequestEntity(entity);
            }
            httpClient.executeMethod(postMethod);
            if (postMethod.getStatusCode() == HttpStatus.SC_OK) {
                result = castString(postMethod.getResponseBodyAsStream());
            }
        } catch (ConnectTimeoutException e) {
            logger.error(url + ", 连接超时");
        } catch (SocketTimeoutException e) {
            logger.error(url + ", 响应超时");
        } catch (Exception e) {
            logger.error(url + ", Http Post请求异常！", e);
        } finally {
            if (postMethod != null) {
                postMethod.releaseConnection();
            }
        }
        return result;
    }

    /**
     * 输入流转为String 型
     *
     * @param is      流
     * @param charset 字符编码
     * @return
     */
    public static String castString(InputStream is, String charset) {
        StringBuilder sb = new StringBuilder();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(is, charset));
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (Exception e) {
            logger.error("输入流转换异常！", e);
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                logger.error("关闭资源出错！", e);
            }
        }
        return sb.toString();
    }

    /**
     * 输入流转为String 型
     *
     * @param is
     * @return
     */
    private static String castString(InputStream is) {
        return castString(is, "UTF-8");
    }

    /**
     * Http Get请求(默认UTF-8编码)
     *
     * @param url         请求地址
     * @param connTimeout 连接超时时间
     * @param soTimeout   读取数据超时时间
     * @return
     */
    public static String httpGet(String url, int connTimeout, int soTimeout) {
        return httpGet(url, "UTF-8", connTimeout, soTimeout);
    }

    /**
     * Http Get请求(默认UTF-8编码)
     *
     * @param url 请求地址
     * @param charset 请求编码
     * @return
     */
    public static String httpGet(String url, String charset) {
        return httpGet(url, charset, 2000, 2000);
    }

    /**
     * Http Get请求(2秒连接超时，2秒读取超时)
     *
     * @param url 请求地址
     * @return
     */
    public static String httpGet(String url) {
        return httpGet(url, 2000, 2000);
    }


    /**
     * Http Post请求(2秒连接超时，2秒读取超时)
     *
     * @param url    请求地址
     * @param params 请求参数
     * @return
     */
    public static String httpPost(String url, Map<String, String> params) {
        return httpPost(url, params, 2000, 2000);
    }

    /**
     * Http Post请求(2秒连接超时，2秒读取超时)
     *
     * @param url    请求地址
     * @param entity 请求参数
     * @return
     */
    public static String httpPost(String url, RequestEntity entity) {
        return httpPost(url, entity, 2000, 2000);
    }
    /**
     * 后台通过HTTP模拟Post上传文件
     * @param urlStr
     * @param textMap
     * @param fileMap
     * @return
     * @throws Exception
     */
    public static String formUpload(String urlStr, Map<String, String> textMap,
                                    Map<String, File> fileMap) {
    	String res = "";
        HttpURLConnection conn = null;
        String BOUNDARY = "--------------------------"; // boundary就是request头和上传文件内容的分隔符
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(30000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("User-Agent",
                    "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
            conn.setRequestProperty("Content-Type",
                    "multipart/form-data; boundary=" + BOUNDARY);

            OutputStream out = new DataOutputStream(conn.getOutputStream());
            // text
            if (textMap != null) {
                StringBuffer strBuf = new StringBuffer();
                Iterator iter = textMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }
                    strBuf.append("\r\n").append("--").append(BOUNDARY)
                            .append("\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""
                            + inputName + "\"\r\n\r\n");
                    strBuf.append(inputValue);
                }
                out.write(strBuf.toString().getBytes());
            }

            // file
            if (fileMap != null) {
                Iterator iter = fileMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    File file = (File) entry.getValue();
                    if (file == null) {
                        continue;
                    }
                    String filename = file.getName();
                    String contentType = new MimetypesFileTypeMap()
                            .getContentType(file);
                    if(!"".equals(contentType)){
                    	if (filename.endsWith(".png")) {
                    		contentType = "image/png";
                    	}else if (filename.endsWith(".jpg") || filename.endsWith(".jpeg") || filename.endsWith(".jpe")) {
                    		contentType = "image/jpeg";
                    	}else if (filename.endsWith(".gif")) {
                    		contentType = "image/gif";
                    	}else if (filename.endsWith(".ico")) {
                    		contentType = "image/image/x-icon";
                    	}
                    }
                    if (contentType == null || contentType.equals("")) {
                        contentType = "application/octet-stream";
                    }

                    StringBuffer strBuf = new StringBuffer();
                    strBuf.append("\r\n").append("--").append(BOUNDARY)
                            .append("\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""
                            + inputName + "\"; filename=\"" + filename
                            + "\"\r\n");
                    strBuf.append("Content-Type:" + contentType + "\r\n\r\n");

                    out.write(strBuf.toString().getBytes());

                    DataInputStream in = new DataInputStream(
                            new FileInputStream(file));
                    int bytes = 0;
                    byte[] bufferOut = new byte[1024];
                    while ((bytes = in.read(bufferOut)) != -1) {
                        out.write(bufferOut, 0, bytes);
                    }
                    in.close();
                }
            }

            byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
            out.close();

            // 数据返回
            StringBuffer strBuf = new StringBuffer();
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    conn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                strBuf.append(line).append("\n");
            }
            res = strBuf.toString();
            reader.close();
            reader = null;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }
        return res;
    }

    //将request参数转成String格式
    public static String getRequestString(HttpServletRequest request){
        String returnStr = null;
        BufferedReader streamReader = null;
        try {
            // 获取输入流
            streamReader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));

            // 写入数据到Stringbuilder
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = streamReader.readLine()) != null) {
                sb.append(line);
            }
            returnStr = sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                streamReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return returnStr;
    }

    public static String getBaseURl(HttpServletRequest request) {
        String scheme = request.getScheme();
        String serverName = request.getServerName();
        int serverPort = request.getServerPort();
        String contextPath = request.getContextPath();
        StringBuffer url =  new StringBuffer();
        url.append(scheme).append("://").append(serverName);
        if ((serverPort != 80) && (serverPort != 443)) {
            url.append(":").append(serverPort);
        }
        url.append(contextPath);
        if(url.toString().endsWith("/")){
            url.append("/");
        }
        return url.toString();
    }
}
